fix(status): serve menubar-json status from a disk-persisted snapshot to eliminate per-poll re-parse latency - #999
Open
dgabehar wants to merge 2 commits into
Conversation
added 2 commits
August 14, 2026 14:38
… to eliminate per-poll re-parse latency codeburn status --format menubar-json took 25-90+ seconds per call because the menubar app spawns a fresh CLI process per poll, so every call re-JSON.parse'd the full session-cache blob and re-ran the full aggregation pipeline with no cross-process reuse. Adds a disk-persisted status snapshot keyed by a cheap corpus fingerprint (stat-only, no content read), with a settle-window debounce so rapid-fire source writes coalesce into one recompute instead of one per poll.
… to buildMenubarPayloadForRange
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
codeburn status --format menubar-jsontook 25-90+ seconds per callregardless of cache state, causing the polling CodeBurnMenubar.app to
stall/stop refreshing. Root cause (confirmed via live profiling): the
menubar spawns a fresh CLI process per poll, so every call re-parses the
full session-cache blob and re-runs the full aggregation pipeline with
zero cross-process reuse — none of the existing in-process caches
(parser.ts's TTL/burst maps, session-cache.ts's cacheMemo) ever survive
between polls.
This adds a disk-persisted status snapshot keyed by a cheap corpus
fingerprint (stat-only pass over discovered sources — dev/ino/mtime/size,
no session-cache.json parse, no transcript content read), with a
settle-window debounce (CODEBURN_STATUS_SNAPSHOT_SETTLE_MS, default
2000ms, capped 60000ms) so rapid-fire source writes coalesce into one
recompute instead of one per poll tick.
Related
#971 covers the same general problem class (expensive redundant
per-invocation recompute) from a different angle — a resident
codeburn servedaemon sometimes being bypassed on cold start. This PRis orthogonal to that: the menubar's
status --format menubar-jsonpathhas no resident-process story at all today (a fresh CLI process every
poll, always), so the fix here is a disk-persisted snapshot rather than
daemon-sharing. Happy to reconcile approaches if useful once #972 lands.
Changes
src/session-cache.ts— disk-persisted status snapshot(
loadStatusSnapshot/saveStatusSnapshot) keyed by corpus fingerprintguard against a payload-shape drift across binary upgrades; orphaned
temp-file sweep extended to cover the new file.
src/parser.ts—computeCorpusFingerprint, a stat-only pass overevery discovered source (expanding Claude's directory-shaped sources
to their actual
.jsonlfiles first, since a directory's own mtimedoesn't move when an existing file inside it is rewritten in place).
src/main.ts— wires thestatus --format menubar-jsonpath to checkthe snapshot before parsing/aggregating, and to persist a fresh one
after a real recompute; a single shared options object now feeds both
the cache key and the
buildMenubarPayloadForRangecall so they can'tdrift apart.
tests/cli-status-menubar.test.ts— new coverage: snapshot-hitbyte-identical output, debounce-defer during the settle window,
reflect-after-settle.
SPEC-perf-cache-fix.md— design write-up (root-cause investigation,why the debounce lives in the snapshot layer rather than
reconcileFile, and why a first attempt at the latter was reverted).Test plan
npm test— full suite passes, including the newtests/cli-status-menubar.test.tscoverage.npx tsc --noEmitclean.~18-23s (unchanged — that's the underlying parse+aggregate cost, not
addressed by this fix), settled repeat call ~2s, byte-identical
payload.
npm linkand run against the realCodeBurnMenubar.app.
Checklist
docs/release-notes.md+README.md)npm testgreen